/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = sip_resp.c                                         */
/*  NOTE      =                                                    */
/*  DATE      = 2015/07/10 by songbb                               */
/*******************************************************************/

#include "conntrack.h"
#include "frct_comm.h"
#include "frreport_comm.h"

#include "sip_core.h"
#include "sip_comm.h"
#include "sip_resp.h"
#include "sip_sdp.h"

extern void *g_p_apm_context;
extern int g_i_connect_in_collect;

/*******************************************************************************
*  FUNC     :  解析SIP响应
*  ARGS     :  *p_st_conn                               (ct信息)
*           :  *p_st_sess                               (SIP私有的session)
*           :  *p_st_sip_packet                         (SIP数据包)
*           :  *p_st_hash_report                        (数据上报)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int __sip_unpack_resp(Conntrack *p_st_conn
                    , L7session_sip *p_st_sess
                    , L7_sip_packet *p_st_sip_packet
                    , Frhash_header *p_st_hash_report)
{
    L7_session *p_st_session = frct_get_session(p_st_conn);
    L7session_sip_private *p_st_session_private = (L7session_sip_private *) frct_get_session_private(p_st_session);
    Frhash_header *p_hash_stmt = p_st_session_private->p_hash_stmt;
    int i_pos_eoh = 0;
    int i_pos_header_fields = 0;
    int i_pos_colon = 0;
    char *p_field_name = NULL;
    char *p_field_value = NULL;
    char *p_field_value2 = NULL;
    char *p_field_value_whole = NULL;
    int i_pos_line_end = 0;
    uint8_t tmp;
    int i_append_first_value = FR_NO;
    Frstr *p_frstr = NULL;
    char arr_version[8];
    char *p_status_code = NULL;
    int i_pos_firstline_end = 0;
    int i_response_codestring_len = 0;
    long l_status_code = 0L;
    char *p_response_codestring = NULL;
    Frreport_body_data *p_st_body = NULL;
    char *p_report_key = NULL;
    int i_report_key_len = 0;
    char *p_code_string = NULL;
    int i_dissect_sdp = FR_NO;
    char *p_content_body = NULL;
    int i_content_len = 0;
    char arr_info[64] = {'\0'};
    Frreport_data *p_st_report_data = NULL;
    char *p_branch = NULL;
    L7_sip_stmt *p_st_sip_stmt = NULL;
    Frlist_node *p_st_node = NULL;

    // Status-Line  =  SIP-Version SP Status-Code SP Reason-Phrase CRLF

    // 校验SIP-Version字段
    if (bytebuff_get_bytes_at(p_st_sip_packet->p_st_packet, 0, strlen(APM_SIP_VERSION""APM_SIP_SP), arr_version) != FR_SUCC)
        goto error;
    if (memcmp(arr_version, APM_SIP_VERSION""APM_SIP_SP, strlen(APM_SIP_VERSION""APM_SIP_SP)) != 0)
        goto error;

    // 取Status-Code字段
    if ((p_status_code = (char *) frmalloc(sizeof(char) * (4))) == NULL)
    {
        SIP_MALLOCK_ERR;
        goto error;
    }
    if (bytebuff_get_bytes_at(p_st_sip_packet->p_st_packet, strlen(APM_SIP_VERSION""APM_SIP_SP), 3, p_status_code) != FR_SUCC)
        goto error;
    if (p_status_code[0] < '1' || p_status_code[0] > '6' ||
        p_status_code[1] < '0' || p_status_code[1] > '9' ||
        p_status_code[2] < '0' || p_status_code[2] > '9')
        goto error;
    p_status_code[3] = '\0';
    l_status_code = atoi(p_status_code);
    SIP_PRINT_FATAL("status code:[%ld]\n", l_status_code);

    if ((p_st_body = frreport_body_new_l7(p_st_conn)) == NULL)
        goto error;

    // 查找CRLFCRLF
    if (bytebuff_memstr(p_st_sip_packet->p_st_packet, 0, bytebuff_length(p_st_sip_packet->p_st_packet), APM_SIP_EOH, (int) strlen(APM_SIP_EOH), &i_pos_eoh) != FR_SUCC)
        goto error;

    // 取Reason-Phrase字段
    // 查找first line的结束位置
    if (bytebuff_memstr(p_st_sip_packet->p_st_packet, 0, i_pos_eoh + (int) strlen(APM_SIP_EOH), APM_SIP_EOL, strlen(APM_SIP_EOL), &i_pos_firstline_end) != FR_SUCC)
        goto error;
    i_response_codestring_len = i_pos_firstline_end - strlen(APM_SIP_VERSION""APM_SIP_SP) - 3 - strlen(APM_SIP_SP);
    if ((p_response_codestring = (char *) frmalloc(sizeof(char) * (i_response_codestring_len + 1))) == NULL)
    {
        SIP_MALLOCK_ERR;
        goto error;
    }
    if (bytebuff_get_bytes_at(p_st_sip_packet->p_st_packet,
                              strlen(APM_SIP_VERSION""APM_SIP_SP) + 3 + strlen(APM_SIP_SP),
                              (unsigned int) i_response_codestring_len,
                              p_response_codestring) != FR_SUCC)
        goto error;
    p_response_codestring[i_response_codestring_len] = '\0';

    if ((p_code_string = (char *) frmalloc(sizeof(char) * (4 + i_response_codestring_len + 1))) == NULL)
    {
        SIP_MALLOCK_ERR;
        goto error;
    }
    snprintf(p_code_string, (size_t) (4 + i_response_codestring_len + 1), "%s %s", p_status_code, p_response_codestring);
    SIP_PRINT_FATAL("p_response_codestring:[%s]\n", p_response_codestring);
    if (frreport_body_l7_add_long(p_st_body, APM_REPORT_KEY_RESP_CODE, l_status_code) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_RESP_CODE_STRING, p_code_string) != FR_SUCC)
        goto error;
    sip_free((void **) &p_response_codestring);
    sip_free((void **) &p_code_string);

    // 确定header fields的起始行位置
    if (bytebuff_memstr(p_st_sip_packet->p_st_packet, 0, i_pos_eoh + (int) strlen(APM_SIP_EOH), APM_SIP_EOL, strlen(APM_SIP_EOL), &i_pos_header_fields) != FR_SUCC)
        goto error;
    i_pos_header_fields += strlen(APM_SIP_EOL);

    while (i_pos_header_fields < i_pos_eoh)
    {
        // 查找头域分隔符:的位置
        if (bytebuff_memstr(p_st_sip_packet->p_st_packet, i_pos_header_fields, i_pos_eoh + (int) strlen(APM_SIP_EOH), APM_SIP_COLON, strlen(APM_SIP_COLON), &i_pos_colon) != FR_SUCC)
            goto error;
        i_pos_colon -= i_pos_header_fields;
        if (i_pos_colon == 0)
            goto error;
        i_pos_colon += i_pos_header_fields;
        // 取field name值
        if ((p_field_name = (char *) frmalloc(sizeof(char) * (i_pos_colon - i_pos_header_fields + 1))) == NULL)
        {
            SIP_MALLOCK_ERR;
            goto error;
        }
        if (bytebuff_get_bytes_at(p_st_sip_packet->p_st_packet, i_pos_header_fields, (unsigned int) (i_pos_colon - i_pos_header_fields), p_field_name) != FR_SUCC)
            goto error;
        p_field_name[i_pos_colon - i_pos_header_fields] = '\0';
        frtrim(p_field_name);
//        SIP_PRINT_WARN("p_field_name:[%s]\n", p_field_name);
        i_append_first_value = FR_NO;

        // 查找当前行的结束位置
        if (bytebuff_memstr(p_st_sip_packet->p_st_packet, i_pos_colon, i_pos_eoh + (int) strlen(APM_SIP_EOH), APM_SIP_EOL, strlen(APM_SIP_EOL), &i_pos_line_end) != FR_SUCC)
            goto error;
        i_pos_line_end -= i_pos_colon;
        if (i_pos_line_end == 0)
            goto error;
        i_pos_line_end += i_pos_colon;

        // 取field value值
        if ((p_field_value = (char *) frmalloc(sizeof(char) * (i_pos_line_end - i_pos_colon - 1 + 1))) == NULL)
        {
            SIP_MALLOCK_ERR;
            goto error;
        }
        if (bytebuff_get_bytes_at(p_st_sip_packet->p_st_packet, i_pos_colon + 1, (unsigned int) (i_pos_line_end - i_pos_colon - 1), p_field_value) != FR_SUCC)
            goto error;
        p_field_value[i_pos_line_end - i_pos_colon - 1] = '\0';
        frtrim(p_field_value);

        i_pos_header_fields = i_pos_line_end + strlen(APM_SIP_EOL);

        if (i_pos_header_fields < i_pos_eoh)
        {
            if (bytebuffer_get_at(p_st_sip_packet->p_st_packet, i_pos_header_fields, &tmp) != FR_SUCC)
                goto error;
            while (tmp == ' ' || tmp == '\t') // 多行field value
            {
                // 查找当前行的结束位置
                if (bytebuff_memstr(p_st_sip_packet->p_st_packet, i_pos_header_fields, i_pos_eoh + (int) strlen(APM_SIP_EOH), APM_SIP_EOL, strlen(APM_SIP_EOL), &i_pos_line_end) != FR_SUCC)
                    goto error;
                i_pos_line_end -= i_pos_header_fields;
                if (i_pos_line_end == 0)
                    goto error;
                i_pos_line_end += i_pos_header_fields;

                // 先插入第一个value
                if (i_append_first_value == FR_NO)
                {
                    if ((p_frstr = frstr_new(64)) == NULL)
                        goto error;
                    if (frstr_append(p_frstr, p_field_value, strlen(p_field_value)) != FR_SUCC)
                        goto error;
                    sip_free((void **) &p_field_value);
                    i_append_first_value = FR_YES;
                }

                // 取field value值
                if ((p_field_value2 = (char *) frmalloc(sizeof(char) * (i_pos_line_end - i_pos_header_fields + 1))) == NULL)
                {
                    SIP_MALLOCK_ERR;
                    goto error;
                }
                if (bytebuff_get_bytes_at(p_st_sip_packet->p_st_packet, i_pos_header_fields, (unsigned int) (i_pos_line_end - i_pos_header_fields), p_field_value2) != FR_SUCC)
                    goto error;
                p_field_value2[i_pos_line_end - i_pos_header_fields] = '\0';
                frtrim(p_field_value2);
                if (frstr_append(p_frstr, " ,", 2) != FR_SUCC)
                    goto error;
                if (frstr_append(p_frstr, p_field_value2, strlen(p_field_value2)) != FR_SUCC)
                    goto error;
                sip_free((void **) &p_field_value2);
                i_pos_header_fields = i_pos_line_end + strlen(APM_SIP_EOL);

                if (i_pos_header_fields >= i_pos_eoh)
                    break;
                if (bytebuffer_get_at(p_st_sip_packet->p_st_packet, i_pos_header_fields, &tmp) != FR_SUCC)
                    goto error;
            }
        }

        if (i_append_first_value == FR_YES)
            p_field_value_whole = frstr_free2(&p_frstr);
        else
        {
            p_field_value_whole = p_field_value;
            p_field_value = NULL;
        }
//        SIP_PRINT_WARN("p_field_value_whole:[%s]\n", p_field_value_whole);

        /**
         * XXX: 有可能会同时存在多个Via头,每经过一个sip节点时,会在前面增加一个Via头,所以取第1个Via的branch值做hash存储
         */
        if (strcasecmp(p_field_name, "Via") == 0 && p_branch == NULL)
        {
            if (sip_get_branch_from_via(p_field_value_whole, &p_branch) != FR_SUCC)
                goto error;
            if ((p_st_node = frhash2_getStr(p_hash_stmt, p_branch, (unsigned int) strlen(p_branch))) == NULL)
                goto error;
            if ((p_st_sip_stmt = (L7_sip_stmt *) FRLIST_GET_NODE_DATA(p_st_node)) == NULL)
                goto error;

            if (p_st_sip_stmt->em_req_method == SIP_METHOD_TYPE_UNKNOWN ||
                (p_st_sip_stmt->em_req_method != SIP_METHOD_TYPE_REGISTER && p_st_sip_stmt->em_req_method != SIP_METHOD_TYPE_BYE &&
                 (p_st_sip_stmt->p_report_comm == NULL || p_st_sip_stmt->p_report_req == NULL)))
            {
                SIP_PRINT_ALERT("Ignore this response\n");
                frreport_body_free(&p_st_body);
                goto success;
            }

            if (l_status_code >= 100 && l_status_code < 200)
            {
                if (p_st_sip_stmt->st_resp_start_timestamp.tv_sec == 0 && p_st_sip_stmt->st_resp_start_timestamp.tv_usec == 0)
                {
                    p_st_sip_stmt->st_resp_start_timestamp.tv_sec = p_st_sip_packet->st_timestamp_first.tv_sec;
                    p_st_sip_stmt->st_resp_start_timestamp.tv_usec = p_st_sip_packet->st_timestamp_first.tv_usec;
                    p_st_sip_stmt->ul_resp_server_time_us = (unsigned long) frtime_diff(&(p_st_sip_stmt->st_req_end_timestamp), &(p_st_sip_stmt->st_resp_start_timestamp));
                }
                p_st_sip_stmt->ul_resp_bytes += p_st_sip_packet->ui_length;
                frreport_body_free(&p_st_body);
                goto success;
            }
        }

        if(strcasecmp(p_field_name, "Server") == 0)
        {
            sip_free((void **) &(p_st_sess->p_server));
            p_st_sess->p_server = frstrdup(p_field_value_whole);
        }
        if (p_st_sip_stmt && p_st_sip_stmt->em_req_method == SIP_METHOD_TYPE_INVITE)
        {
            if (strcasecmp(p_field_name, "Content-Type") == 0 && strcasecmp(p_field_value_whole, "application/sdp") == 0)
                i_dissect_sdp = FR_YES;
        }

        if (frstrlower(p_field_name, strlen(p_field_name)) != FR_SUCC)
            goto error;
        i_report_key_len = strlen(APM_SIP_REPORT_RESP_HDR_PREFIX) + strlen(p_field_name) + 1;
        if ((p_report_key = (char *) frmalloc(sizeof(char) * i_report_key_len)) == NULL)
        {
            SIP_MALLOCK_ERR;
            goto error;
        }
        snprintf(p_report_key, (size_t) i_report_key_len, APM_SIP_REPORT_RESP_HDR_PREFIX"%s", p_field_name);
        if (frreport_body_l7_add_str(p_st_body, p_report_key, p_field_value_whole) != FR_SUCC)
            goto error;

        sip_free((void **) &p_field_name);
        sip_free((void **) &p_field_value_whole);
        sip_free((void **) &p_report_key);
    }

    // 没找到对应的请求
    if (p_st_sip_stmt == NULL)
        goto error;

    // 分析SDP协议
    if (i_dissect_sdp == FR_YES &&
        p_st_sip_packet->ui_content_length > 0 &&
        bytebuff_length(p_st_sip_packet->p_st_packet) - i_pos_eoh - strlen(APM_SIP_EOH) > 0)
    {
        i_content_len = (int) (bytebuff_length(p_st_sip_packet->p_st_packet) - i_pos_eoh - strlen(APM_SIP_EOH));
        if ((p_content_body = (char *) frmalloc(sizeof(char) * i_content_len)) == NULL)
        {
            SIP_MALLOCK_ERR;
            goto error;
        }
        if (bytebuff_get_bytes_at(p_st_sip_packet->p_st_packet, (int) (i_pos_eoh + strlen(APM_SIP_EOH)), (unsigned int) (i_content_len), p_content_body) != FR_SUCC)
            goto error;
        if (sip_dissect_sdp(p_st_sip_stmt, p_content_body, i_content_len, FR_NO) != FR_SUCC)
            goto error;
        if (frreport_body_l7_add_str(p_st_body, APM_SIP_REPORT_REQ_BODY, p_content_body) != FR_SUCC)
            goto error;
        sip_free((void **) &p_content_body);

        if (g_i_connect_in_collect == FR_NO)
        {
            // 设置关联链路
            sip_set_child_conn(p_st_conn, p_st_sip_stmt);
        }
    }

    if (p_st_sip_stmt->em_req_method == SIP_METHOD_TYPE_REGISTER)
    {
        if (p_st_sip_stmt->i_is_register == FR_YES)
        {
            p_st_sess->st_registered_timestamp.tv_sec = p_st_sip_packet->st_timestamp_first.tv_sec;
            p_st_sess->st_registered_timestamp.tv_usec = p_st_sip_packet->st_timestamp_first.tv_usec;
            if (l_status_code == 200)
            {
                if (p_st_sip_stmt->p_username)
                    snprintf(arr_info, sizeof(arr_info), "%s login", p_st_sip_stmt->p_username);
                else
                    snprintf(arr_info, sizeof(arr_info), "login");

                p_st_report_data = frreport_update_create(p_st_conn, APM_REPORT_UPDATE_LOGON, arr_info, &(p_st_sip_packet->st_timestamp_first));
            }
            else
            {
                if (p_st_sip_stmt->p_username)
                    snprintf(arr_info, sizeof(arr_info), "%s login reject", p_st_sip_stmt->p_username);
                else
                    snprintf(arr_info, sizeof(arr_info), "login reject");

                p_st_report_data = frreport_update_create(p_st_conn, APM_REPORT_UPDATE_LOGON_REJECT, arr_info, &(p_st_sip_packet->st_timestamp_last));
            }

            if (frreport_send(g_p_apm_context, &p_st_report_data) == FR_SUCC)
                SIP_PRINT_WARN("frreport_send success\n");
            else
            {
                frreport_data_free(&p_st_report_data);
                SIP_PRINT_WARN("frreport_send fail\n");
            }
        }

//        frreport_body_free(&p_st_body);
//        goto success;
    }
    else if (p_st_sip_stmt->em_req_method == SIP_METHOD_TYPE_BYE)
    {
        if (p_st_sip_stmt->p_username)
            snprintf(arr_info, sizeof(arr_info), "%s logout", p_st_sip_stmt->p_username);
        else
            snprintf(arr_info, sizeof(arr_info), "logout");

        p_st_report_data = frreport_update_create(p_st_conn, APM_REPORT_UPDATE_LOGOUT, arr_info, &(p_st_sip_packet->st_timestamp_last));

        if (frreport_send(g_p_apm_context, &p_st_report_data) == FR_SUCC)
            SIP_PRINT_WARN("frreport_send success\n");
        else
        {
            frreport_data_free(&p_st_report_data);
            SIP_PRINT_WARN("frreport_send fail\n");
        }

        frreport_body_free(&p_st_body);
        goto success;
    }

    if (FRREPORT_BODY_L7LIST_SET_COMM(p_st_body, &(p_st_sip_stmt->p_report_comm)) != FR_SUCC)
        goto error;
    if (FRREPORT_BODY_L7LIST_SET_REQ(p_st_body, &(p_st_sip_stmt->p_report_req)) != FR_SUCC)
        goto error;
    if (p_st_sip_stmt->st_resp_start_timestamp.tv_sec != 0 || p_st_sip_stmt->st_resp_start_timestamp.tv_usec != 0)
    {
        if (frreport_body_l7_add_timeval(p_st_body, APM_REPORT_KEY_RESP_START_TIMESTAMP, &(p_st_sip_stmt->st_resp_start_timestamp)) != FR_SUCC)
            goto error;
    }
    else
    {
        if (frreport_body_l7_add_timeval(p_st_body, APM_REPORT_KEY_RESP_START_TIMESTAMP, &(p_st_sip_packet->st_timestamp_first)) != FR_SUCC)
            goto error;
    }
    if (frreport_body_l7_add_timeval(p_st_body, APM_REPORT_KEY_RESP_END_TIMESTAMP, &(p_st_sip_packet->st_timestamp_last)) != FR_SUCC)
        goto error;
    if (p_st_sip_stmt->ul_resp_server_time_us != 0L)
    {
        if (frreport_body_l7_add_long(p_st_body, APM_REPORT_KEY_RESP_SERVER_TIME_US, p_st_sip_stmt->ul_resp_server_time_us) != FR_SUCC)
            goto error;
    }
    else if (p_st_sip_stmt->st_resp_start_timestamp.tv_sec != 0 || p_st_sip_stmt->st_resp_start_timestamp.tv_usec != 0)
    {
        if (frreport_body_l7_add_long(p_st_body, APM_REPORT_KEY_RESP_SERVER_TIME_US, frtime_diff(&(p_st_sip_stmt->st_req_end_timestamp), &(p_st_sip_stmt->st_resp_start_timestamp))) != FR_SUCC)
            goto error;
    }
    else
    {
        if (frreport_body_l7_add_long(p_st_body, APM_REPORT_KEY_RESP_SERVER_TIME_US, frtime_diff(&(p_st_sip_stmt->st_req_end_timestamp), &(p_st_sip_packet->st_timestamp_first))) != FR_SUCC)
            goto error;
    }
    if (p_st_sip_stmt->st_resp_start_timestamp.tv_sec != 0 || p_st_sip_stmt->st_resp_start_timestamp.tv_usec != 0)
    {
        if (frreport_body_l7_add_long(p_st_body, APM_REPORT_KEY_RESP_DOWNLOAD_TIME_US, frtime_diff(&(p_st_sip_stmt->st_resp_start_timestamp), &(p_st_sip_packet->st_timestamp_last))) != FR_SUCC)
            goto error;
    }
    else
    {
        if (frreport_body_l7_add_long(p_st_body, APM_REPORT_KEY_RESP_DOWNLOAD_TIME_US, frtime_diff(&(p_st_sip_packet->st_timestamp_first), &(p_st_sip_packet->st_timestamp_last))) != FR_SUCC)
            goto error;
    }
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_RESP_DATA_BYTES, p_st_sip_packet->ui_length) != FR_SUCC)
        goto error;
    if (g_i_connect_in_collect == FR_YES)
    {
        // 上报RTP相关的信息
        sip_report_media_info(p_st_sip_stmt, p_st_body);
    }

    if (sip_report_data(p_st_conn, FR_NO, p_st_body, p_st_hash_report) != FR_SUCC)
        goto error;

success:
    if (l_status_code >= 200 && p_branch)
        frhash2_delStr(p_hash_stmt, p_branch, (unsigned int) strlen(p_branch), sip_stmt_node_free);
    sip_free((void **) &p_branch);
    sip_free((void **) &p_status_code);
    sip_free((void **) &p_field_name);
    sip_free((void **) &p_field_value_whole);
    sip_free((void **) &p_report_key);
    return FR_SUCC;
error:
    if (p_branch)
        frhash2_delStr(p_hash_stmt, p_branch, (unsigned int) strlen(p_branch), sip_stmt_node_free);
    sip_free((void **) &p_branch);
    sip_free((void **) &p_response_codestring);
    sip_free((void **) &p_field_name);
    sip_free((void **) &p_field_value2);
    sip_free((void **) &p_field_value_whole);
    frstr_free(&p_frstr);
    sip_free((void **) &p_status_code);
    sip_free((void **) &p_content_body);
    sip_free((void **) &p_code_string);
    sip_free((void **) &p_field_value);
    sip_free((void **) &p_report_key);
    frreport_body_free(&p_st_body);
    frreport_data_free(&p_st_report_data);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  分析SIP响应
*  ARGS     :  *p_st_conn                               (ct信息)
*           :  *p_st_sess                               (SIP私有的session)
*           :  *p_st_sip_packet                         (SIP数据包)
*           :  *p_st_hash_report                        (数据上报)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int sip_analyze_resp(Conntrack *p_st_conn
                    , L7session_sip *p_st_sess
                    , L7_sip_packet *p_st_sip_packet
                    , Frhash_header *p_st_hash_report)
{
    return __sip_unpack_resp(p_st_conn, p_st_sess, p_st_sip_packet, p_st_hash_report);
}
